package com.zmn.plat.business.impl.channel;

import com.alibaba.fastjson.JSONObject;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto.AreaDTO;
import com.zmn.common.dto.VtDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.redis.lock.DistributedLock;
import com.zmn.manager.redis.lock.DistributedLockUtils;
import com.zmn.plat.business.interfaces.channel.ChannelCategBService;
import com.zmn.plat.business.interfaces.channel.ChannelServiceCategoryBService;
import com.zmn.plat.common.constant.RedisKeyConstant;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.dto.category.CategoryDRO;
import com.zmn.plat.common.dto.category.CategoryInfoDRO;
import com.zmn.plat.common.dto.channel.category.ChannelCategorySimpleSpellDIO;
import com.zmn.plat.common.dto.channel.category.ChannelCategorySimpleSpellDRO;
import com.zmn.plat.common.dto.servcategory.ServCategoryDRO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.manager.dictionary.ChannelDict;
import com.zmn.plat.manager.dictionary.ProductDict;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.category.CategoryInfoDTO;
import com.zmn.plat.model.entity.category.ServCategAndCategTwoQuery;
import com.zmn.plat.model.entity.channel.Channel;
import com.zmn.plat.model.entity.channel.ChannelServiceArea;
import com.zmn.plat.model.entity.channel.ChannelServiceAreaCategory;
import com.zmn.plat.model.entity.channel.ChannelServiceAreaQuery;
import com.zmn.plat.model.entity.product.ServProduct;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.persistence.interfaces.channel.ChannelServiceAreaDAO;
import com.zmn.plat.services.interfaces.area.BaseAreaService;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.channel.ChannelService;
import com.zmn.plat.services.interfaces.channel.ChannelServiceAreaCategoryService;
import com.zmn.plat.services.interfaces.channel.ChannelServiceAreaService;
import com.zmn.plat.services.interfaces.channel.ChannelServiceCategoryService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.servcategory.ServAssCategoryService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import lombok.extern.log4j.Log4j2;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Log4j2
public class ChannelCategBServiceImpl implements ChannelCategBService {

    @Resource
    ChannelServiceAreaCategoryService serviceAreaCategoryService;
    @Resource
    ChannelServiceCategoryService categoryService;
    @Resource
    BaseCategoryService baseCategoryService;
    @Resource
    ChannelService channelService;
    @Resource
    private ServCategoryService servCategoryService;
    @Resource
    private ChannelServiceCategoryService channelServiceCategoryService;
    @Resource
    private ChannelServiceCategoryBService channelServiceCategoryBService;
    @Resource
    private BaseAreaService baseAreaService;
    @Resource
    ChannelServiceAreaService channelServiceAreaService;
    @Resource
    ChannelServiceAreaCategoryService channelServiceAreaCategoryService;
    @Resource
    ServProductService servProductService;
    @Resource
    ChannelCategBService channelCategBService;
    @Resource
    ServAssCategoryService servAssCategoryService;
    @Resource
    ChannelServiceAreaDAO channelServiceAreaDAO;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'servcateg:categall:channel:'+#p0+#p1+#p2", unless = "#result == null")
    public List<ServCategAndCategTwoQuery> listServCategAndCategTwoQueryByChannelIdAndShowType(Integer channelId, Integer cityId, Integer showType) {
        try {
            if (NumberUtil.isPositiveInteger(channelId)) {
                channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
            }
        } catch (PlatException e) {
            return Collections.emptyList();
        }
        List<ServCategAndCategTwoQuery> servCategAndCategTwoQueryList;

        /**
         * 描述: 不要问为什么这么写，产品设计的逻辑就这么绕
         */
        // 查询渠道是否开通区域
        ChannelServiceAreaQuery query = new ChannelServiceAreaQuery();
        query.setChannelId(channelId);
        Integer count1 = channelServiceAreaDAO.countByQuery(query);

        if (count1 > 0) {
            // 查询渠道是否开通具体的城市
            query.setCityId(cityId);
            Integer count2 = channelServiceAreaDAO.countByQuery(query);
            if (count2 > 0) {
                // 查询渠道城市开通的品类
                servCategAndCategTwoQueryList = serviceAreaCategoryService.listServCategAndCategTwoQueryByChannelIdAndCityIdAndShowType(channelId, cityId, showType);
                if (CollectionUtils.isEmpty(servCategAndCategTwoQueryList)) {
                    // 该城市下未开通任何品类，查询渠道开通的分类
                    servCategAndCategTwoQueryList = categoryService.listServCategAndCategTwoQueryByChannelIdAndShowType(channelId, showType);
                }
            } else {
                // 渠道未开通改城市
                return Collections.emptyList();
            }

        } else {
            // 未开通任何城市，查询渠道开通的分类
            servCategAndCategTwoQueryList = categoryService.listServCategAndCategTwoQueryByChannelIdAndShowType(channelId, showType);
        }
        return servCategAndCategTwoQueryList;
    }

    @Override
    public List<ServCategoryDRO> listServCategoryByChannelId(Integer channelId, Integer showType) {

        if (Objects.isNull(channelId) || Objects.isNull(showType)) {
            log.error("listServCategoryByChannelId参数不能为空：channelId：{}，showType：{}", channelId, showType);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }
        String key = RedisKeyConstant.getKeyServerCategoryByChannelIdAndShowType(channelId, showType);
        String value = redisTemplate.opsForValue().get(key);
        // 缓存中有数据
        if (StringUtil.isNotBlank(value)) {
            if (RedisKeyConstant.NO_DATA.equals(value)) {
                return Collections.emptyList();
            } else {
                return JSONObject.parseArray(value, ServCategoryDRO.class);
            }
        }
        int time = 60;
        String lockKey = RedisKeyConstant.getLockKeyServerCategoryByChannelIdAndShowType(channelId, showType);
        DistributedLock redisLock = DistributedLockUtils.buildReentrantLock(lockKey, time);
        if (redisLock.tryLock()) {
            try {
                channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
                List<ServCategory> list = servCategoryService.listServCategoryByChannelId(channelId, showType);
                List<ServCategoryDRO> categoryList = BeanMapper.mapList(list, ServCategoryDRO.class);
                if (categoryList == null || categoryList.size() == 0) {
                    value = RedisKeyConstant.NO_DATA;
                } else {
                    value = JSONObject.toJSONString(categoryList);
                }
                redisTemplate.opsForValue().set(key, value, 5, TimeUnit.MINUTES);
                return categoryList;
            } finally {
                try {
                    redisLock.unlock();
                } catch (Exception ignored) {
                }
            }
        } else {
            if (redisLock.lock(time, TimeUnit.SECONDS)) {
                try {
                    redisLock.unlock();
                } catch (Exception ignored) {
                }
                return listServCategoryByChannelId(channelId, showType);
            } else {
                log.error("根据渠道id查询开通了分类的渠道id，获取redis锁超时");
                throw new PlatException(PlatErrorCodeDict.ERROR_CODE_TIME_OUT);
            }
        }
    }

    @Override
    public List<CategoryDRO> listCategoryOneByChannelIdAndServCategId(Integer channelId, Integer showType, Integer servCategId) {

        if (Objects.isNull(channelId) || Objects.isNull(showType) || Objects.isNull(servCategId)) {
            log.error("listCategoryOneByChannelIdAndServCategId参数不能为空：channelId：{}，showType：{}，servCategId：{}", channelId, showType, servCategId);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }
        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }
        List<BaseCategory> list = baseCategoryService.listOneCategoryByChannelIdAndServCategId(channelId, showType, servCategId);
        List<CategoryDRO> dros = BeanMapper.mapList(list, CategoryDRO.class);
        return dros;
    }

    @Override
    public List<CategoryInfoDRO> listCategoryByChannelIdAndCategOneId(Integer channelId, Integer showType, Integer categOneId) {
        if (Objects.isNull(channelId) || Objects.isNull(showType) || Objects.isNull(categOneId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<CategoryInfoDTO> list = baseCategoryService.listCategoryByChannelIdAndCategOneId(channelId, showType, categOneId);
        List<CategoryInfoDRO> dros = BeanMapper.mapList(list, CategoryInfoDRO.class);

        return dros;
    }

    @Override
    public List<CategoryInfoDRO> listCategoryByChannelIdAndServCategId(Integer channelId, Integer showType, Integer servCategId) {
        if (Objects.isNull(channelId) || Objects.isNull(showType) || Objects.isNull(servCategId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<CategoryInfoDTO> list = baseCategoryService.listCategoryByChannelIdAndServCategId(channelId, showType, servCategId);
        List<CategoryInfoDRO> dros = BeanMapper.mapList(list, CategoryInfoDRO.class);

        return dros;
    }

    @Override
    public List<Integer> listCategIdByChannelIdAndServCategIdAndCategIds(Integer channelId, Integer servCategId, List<Integer> categIds) {
        if (Objects.isNull(channelId) || Objects.isNull(servCategId) || CollectionUtil.isNullOrEmpty(categIds)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<Integer> list = channelServiceCategoryService.listCategIdByChannelIdAndServCategIdAndCategIds(channelId, servCategId, categIds);

        return list;
    }

    @Override
    public List<CategoryInfoDRO> listShowCategByChannelId(Integer channelId) {
        if (Objects.isNull(channelId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<CategoryInfoDTO> list = baseCategoryService.listShowCategByChannelId(channelId);
        List<CategoryInfoDRO> dros = BeanMapper.mapList(list, CategoryInfoDRO.class);

        return dros;
    }

    @Override
    public List<ServCategoryDRO> listServCategoryByChannelIdAndCityId(Integer channelId, Integer showType, Integer cityId) {
        if (Objects.isNull(channelId) || Objects.isNull(showType) || Objects.isNull(cityId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<ServCategory> list = servCategoryService.listServCategoryByChannelIdAndCityId(channelId, showType, cityId);
        List<ServCategoryDRO> dros = BeanMapper.mapList(list, ServCategoryDRO.class);

        return dros;
    }

    @Override
    public List<ChannelCategorySimpleSpellDRO> listCategoryByChannelIdAndCityIdAndSimpleSpell(ChannelCategorySimpleSpellDIO spellDIO) {
        // 根据渠道ID,城市查询渠道城市开通的服务分类和二级产品分类集合
        List<ServCategAndCategTwoQuery> categIdList = listServCategAndCategTwoQueryByChannelIdAndShowType(spellDIO.getChannelId(), spellDIO.getCityId(), ProductDict.EC_PRODUCT_TYPE);
        if (CollectionUtils.isEmpty(categIdList)) {
            return Collections.emptyList();
        }

        String simpleSpell = spellDIO.getSimpleSpell();

        // 包含一级分类和二级分类
        List<Integer> allProductCategIds = new ArrayList<>();
        // 服务分类ids
        List<Integer> allServCategIds = new ArrayList<>();
        // 分类id和服务分类对应关系，一级分类 key:categOneId,value:servCategId;二级分类key:categId value:categOneId+"_"+servCategId;
        Map<Integer, String> categIdRelationMap = new HashMap<>();
        // 分类查询关联关系
        listByCategIds(allProductCategIds, allServCategIds, categIdList, categIdRelationMap);

        List<ChannelCategorySimpleSpellDRO> retList = new ArrayList<>();
        // 拼音匹配 如果匹配服务分类，那么返回服务分类id，服务分类名称（区分前后台）;
        if (!CollectionUtils.isEmpty(allServCategIds)) {
            List<ServCategory> categoryList = servCategoryService.findByKeys(allServCategIds);
            if (!CollectionUtils.isEmpty(categoryList)) {
                categoryList = categoryList.stream().filter(e -> Objects.equals(e.getShowStatus(), GlobalConsts.YES) && Objects.equals(e.getShowSimpleSpell(), simpleSpell)).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(categoryList)) {
                    retList.addAll(categoryList.stream().map(e -> new ChannelCategorySimpleSpellDRO(e.getCategId(), null, null, e.getShowName())).collect(Collectors.toList()));
                }
            }
        }

        // 产品分类集合
        if (!CollectionUtils.isEmpty(allProductCategIds)) {
            List<BaseCategory> categoryList = baseCategoryService.findByKeys(allProductCategIds);
            if (!CollectionUtils.isEmpty(categoryList)) {
                categoryList = categoryList.stream().filter(e -> Objects.equals(e.getStatus(), GlobalConsts.YES) && Objects.equals(e.getSimpleSpell(), simpleSpell)).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(categoryList)) {
                    for (BaseCategory category : categoryList) {
                        ChannelCategorySimpleSpellDRO dro = null;
                        // 一级
                        if (Objects.equals(category.getLevel(), GlobalConsts.NO)) {
                            dro = new ChannelCategorySimpleSpellDRO(Integer.parseInt(categIdRelationMap.get(category.getCategId())), category.getCategId(), null, category.getName());
                        } else {
                            List<Integer> list = StringUtil.split(categIdRelationMap.get(category.getCategId()), "_", Integer.class);
                            dro = new ChannelCategorySimpleSpellDRO(list.get(1), list.get(0), category.getCategId(), category.getName());
                        }
                        retList.add(dro);
                    }
                }
            }
        }

        return retList;
    }


    @Override
    public List<CategoryInfoDTO> listCategoryByChannelIdAndCityIdAndServCategId(Integer channelId, Integer showType, Integer cityId, Integer servCategId) {
        if (Objects.isNull(channelId) || Objects.isNull(showType) || Objects.isNull(cityId) || Objects.isNull(servCategId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        // 服务分类关联的产品分类（做过滤）
        List<Integer> categIds = Optional.ofNullable(servAssCategoryService.findServAssCategoryByServIdAndShowType(servCategId, showType))
                .orElse(Collections.emptyList())
                .stream()
                .map(m -> m.getCategId())
                .collect(Collectors.toList());
        log.info("服务分类关联的产品分类开通的id{}", categIds);

        // 渠道开通分类
        List<CategoryInfoDTO> list = Optional.ofNullable(baseCategoryService.listCategoryByChannelIdAndCityIdAndServCategId(channelId, cityId, servCategId))
                .orElse(Collections.emptyList())
                .stream()
                .filter(e -> categIds.contains(e.getCategId()))
                .collect(Collectors.toList());
        log.info("渠道开通分类{}", list);

        if (Objects.equals(ProductDict.ERP_PRODUCT_TYPE, showType)) {
            if (CollectionUtil.isNotNullOrEmpty(list)) {
                List<String> unionIds = list.stream().map(e -> servCategId + "-" + e.getOneCategId() + "-" + e.getCategId()).collect(Collectors.toList());
                String[] strings = new String[unionIds.size()];
                unionIds.toArray(strings);
                List<CategoryInfoDTO> result = baseCategoryService.listCategoryByShowCategoryUnionIds(strings);
                return result;
            } else {
                return Collections.EMPTY_LIST;
            }
        } else {
            return list;
        }
    }

    @Override
    public List<CategoryInfoDTO> listCategoryByChannelIdAndCityIdAndServCategIds(Integer channelId, Integer showType, Integer cityId, List<Integer> servCategIds) {
        if (Objects.isNull(channelId) || Objects.isNull(showType) || Objects.isNull(cityId) || CollectionUtil.isNullOrEmpty(servCategIds)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        // 获取渠道城市开通的前台二级分类列表(批量服务分类ID)
        List<CategoryInfoDTO> list = baseCategoryService.listCategoryByChannelIdAndCityIdAndServCategIds(channelId, cityId, servCategIds);

        // 根据渠道城市开通的前台二级分类列表查询关联的后台分类列表
        if (Objects.equals(ProductDict.ERP_PRODUCT_TYPE, showType)) {
            if (CollectionUtil.isNotNullOrEmpty(list)) {
                List<String> unionIds = new ArrayList<>();
                for (Integer servCategId : servCategIds) {
                    List<String> innerUnionIdList = list.stream().map(e -> servCategId + "-" + e.getOneCategId() + "-" + e.getCategId()).collect(Collectors.toList());
                    unionIds.addAll(innerUnionIdList);
                }

                String[] strings = new String[unionIds.size()];
                unionIds.toArray(strings);
                List<CategoryInfoDTO> result = baseCategoryService.listCategoryByShowCategoryUnionIds(strings);

                return result;
            } else {
                return Collections.EMPTY_LIST;
            }
        } else {
            return list;
        }

    }

    @Override
    public List<AreaDTO> listAreaByChannelId(Integer channelId, Integer showType) {
        if (Objects.isNull(channelId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<AreaDTO> areaDTOS = baseAreaService.listByChannelId(channelId);

        return areaDTOS;
    }

    @Override
    public List<AreaDTO> listAreaByChannelIdAndServCategId(Integer channelId, Integer showType, Integer servCategId) {
        if (Objects.isNull(channelId) || Objects.isNull(showType) || Objects.isNull(servCategId)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<AreaDTO> areaDTOS = baseAreaService.listByChannelIdAndServCategId(channelId, showType, servCategId);

        return areaDTOS;
    }

    @Override
    @SuppressWarnings("all")
    @Cacheable(
            key = "'dubbo:channel:showproduct:avaliable:channelId:'+#p0+':cityId:'+#p1", cacheNames = "redis5m", unless = "#result == null || #result.size() <= 0")
    public List<Integer> listChannelShowProductsByChannelIdAndCityId(Integer channelId, Integer cityId) {
        // 判断渠道是否开通分类，如果已开通则取当前渠道，反之取上级渠道信息
        try {
            if (NumberUtil.isPositiveInteger(channelId)) {
                channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
            }
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<ServCategAndCategTwoQuery> servCategAndCategTwoQueries = new ArrayList<>();
        // 当前渠道下开通的城市，如果不存在，那么默认全国
        List<ChannelServiceArea> serviceAreas = channelServiceAreaService.listByChannelId(channelId);
        if (!CollectionUtils.isEmpty(serviceAreas)) {
            // 只考虑城市，不考虑区县
            serviceAreas = serviceAreas.stream().filter(e -> Objects.equals(e.getCityId(), cityId) && Objects.isNull(e.getCountryId())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(serviceAreas)) {
                // 相同的城市只能有一条数据
                List<ChannelServiceAreaCategory> channelServiceAreaCategories = channelServiceAreaCategoryService.listByServiceAreaId(serviceAreas.get(0).getServiceAreaId(), ProductDict.EC_PRODUCT_TYPE);
                if (!CollectionUtils.isEmpty(channelServiceAreaCategories)) {
                    servCategAndCategTwoQueries = channelServiceAreaCategories.stream().map(e -> {
                        ServCategAndCategTwoQuery twoQuery = new ServCategAndCategTwoQuery();
                        twoQuery.setServCategId(e.getServCategId());
                        twoQuery.setCategTwoId(e.getCategId());
                        twoQuery.setCategOneId(e.getCategOneId());
                        return twoQuery;
                    }).collect(Collectors.toList());
                } else {
                    servCategAndCategTwoQueries = channelServiceCategoryService.listServCategAndCategTwoQueryByChannelIdAndShowType(channelId, ProductDict.EC_PRODUCT_TYPE);
                }
            }
        }
        // 不存在开通区域，取渠道的开通分类
        else {
            servCategAndCategTwoQueries = channelServiceCategoryService.listServCategAndCategTwoQueryByChannelIdAndShowType(channelId, ProductDict.EC_PRODUCT_TYPE);
        }

        // 渠道不存在开通的分类，直接返回
        if (CollectionUtils.isEmpty(servCategAndCategTwoQueries)) {
            return Collections.emptyList();
        }

        // 查询渠道已经开通的前台产品
        List<ServProduct> channelSoupportProductList = servProductService.listChannelSupportProductsByCategIds(servCategAndCategTwoQueries, channelId);

        return channelSoupportProductList.stream().map(e -> e.getProductId()).distinct().collect(Collectors.toList());
    }

    @Override
    public List<VtDTO> listServCategoryByChannelIdAndAreaId(Integer channelId, Integer cityId, Integer countyId) {
        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<Integer> servCategIdList = channelCategBService.listCategoriesByCityIdAndCountyId(channelId, cityId, countyId).stream().map(ServCategAndCategTwoQuery::getServCategId).distinct().collect(Collectors.toList());

        if (CollectionUtils.isEmpty(servCategIdList)) {
            return Collections.emptyList();
        }

        // 查询服务分类
        List<ServCategory> servCategories = servCategoryService.findByKeys(servCategIdList);

        return servCategories.stream().map(e -> new VtDTO(e.getCategId(), e.getName())).collect(Collectors.toList());
    }

    @Override
    public List<VtDTO> listProductByChannelIdAndAreaIdAndServCategId(Integer channelId, Integer cityId, Integer countyId, Integer servCategId) {

        try {
            channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            return Collections.emptyList();
        }

        List<ServCategAndCategTwoQuery> servCategAndCategTwoQueries = channelCategBService.listCategoriesByCityIdAndCountyId(channelId, cityId, countyId).stream()
                .filter(e -> Objects.equals(e.getServCategId(), servCategId)).collect(Collectors.toList());

        // 查询渠道已经开通的前台产品
        List<ServProduct> channelSoupportProductList = servProductService.listChannelSupportProductsByCategIds(servCategAndCategTwoQueries, channelId);
        return channelSoupportProductList.stream().map(e -> new VtDTO(e.getProductId(), e.getName())).collect(Collectors.toList());
    }

    @SuppressWarnings("all")
    @Override
    @Cacheable(
            key = "'dubbo:channel:categories:avaliable:channelId:'+#p0+':cityId:'+#p1+':countyId:'+#p2", cacheNames = "redis5m", unless = "#result == null || #result.size() <= 0")
    public List<ServCategAndCategTwoQuery> listCategoriesByCityIdAndCountyId(Integer channelId, Integer cityId, Integer countyId) {
        List<ServCategAndCategTwoQuery> servCategAndCategTwoQueries = new ArrayList<>();
        // 当前渠道下开通的城市，如果不存在，那么默认全国
        List<ChannelServiceArea> serviceAreas = channelServiceAreaService.listByChannelId(channelId);
        if (!CollectionUtils.isEmpty(serviceAreas)) {
            serviceAreas = serviceAreas.stream().filter(e -> Objects.equals(e.getCityId(), cityId)).collect(Collectors.toList());
            // 优先匹配到区县
            List<ChannelServiceArea> channelServiceCountyAreas = serviceAreas.stream().filter(e -> Objects.equals(countyId, e.getCountryId())).collect(Collectors.toList());
            // 只匹配城市
            List<ChannelServiceArea> channelServiceCityAreas = serviceAreas.stream().filter(e -> Objects.isNull(e.getCountryId())).collect(Collectors.toList());
            // 当前生效的区域
            List<ChannelServiceArea> channelAreas = CollectionUtils.isEmpty(channelServiceCountyAreas) ? channelServiceCityAreas : channelServiceCountyAreas;

            if (!CollectionUtils.isEmpty(channelAreas)) {
                // 相同的区域只能有一条数据
                List<ChannelServiceAreaCategory> channelServiceAreaCategories = channelServiceAreaCategoryService.listByServiceAreaId(channelAreas.get(0).getServiceAreaId(), ProductDict.EC_PRODUCT_TYPE);
                if (!CollectionUtils.isEmpty(channelServiceAreaCategories)) {
                    servCategAndCategTwoQueries = channelServiceAreaCategories.stream().map(e -> {
                        ServCategAndCategTwoQuery twoQuery = new ServCategAndCategTwoQuery();
                        twoQuery.setServCategId(e.getServCategId());
                        twoQuery.setCategTwoId(e.getCategId());
                        twoQuery.setCategOneId(e.getCategOneId());
                        return twoQuery;
                    }).collect(Collectors.toList());
                } else {
                    // 区域下没得一个分类，那么取渠道的分类
                    servCategAndCategTwoQueries = channelServiceCategoryService.listServCategAndCategTwoQueryByChannelIdAndShowType(channelId, ProductDict.EC_PRODUCT_TYPE);
                }
            }
        }
        // 不存在开通区域，取渠道的开通分类
        else {
            servCategAndCategTwoQueries = channelServiceCategoryService.listServCategAndCategTwoQueryByChannelIdAndShowType(channelId, ProductDict.EC_PRODUCT_TYPE);
        }
        return servCategAndCategTwoQueries;
    }

    /**
     * 根据渠道ID获取渠道父ID
     *
     * @param channelId
     * @return
     */
    private Integer getParentChannelId(Integer channelId) {
        Integer parentChannelId = GlobalConsts.NO;
        Channel channel = Optional.ofNullable(channelService.findByKey(channelId)).orElse(new Channel());
        if (Objects.equals(ChannelDict.RANK_TWO, channel.getRank()) && NumberUtil.isPositiveInteger(channel.getParentId())) {
            return channel.getParentId();
        }

        return parentChannelId;
    }


    private void listByCategIds(List<Integer> allProductCategIds, List<Integer> allServCategIds, List<ServCategAndCategTwoQuery> relationList, Map<Integer, String> categIdRelationMap) {
        for (ServCategAndCategTwoQuery query : relationList) {
            if (!allServCategIds.contains(query.getServCategId())) {
                allServCategIds.add(query.getServCategId());
            }

            if (!allProductCategIds.contains(query.getCategTwoId())) {
                allProductCategIds.add(query.getCategTwoId());
                categIdRelationMap.put(query.getCategTwoId(), query.getCategOneId() + "_" + query.getServCategId());
            }

            if (!allProductCategIds.contains(query.getCategOneId())) {
                allProductCategIds.add(query.getCategOneId());
                categIdRelationMap.put(query.getCategOneId(), query.getServCategId() + "");
            }
        }
    }
}
